package com.xh3140.android.widget.chart;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;

import com.xh3140.android.widget.chart.scales.AxisScales;
import com.xh3140.android.widget.chart.scales.LinearAxisScales;
import com.xh3140.android.widget.utils.DimenUtils;

/**
 * 坐标系抽象类
 * 定义了基本属性和规范
 * 具体规范需要在子类中实现
 */
@SuppressWarnings("unused")
public abstract class AbstractCoordinatesView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
    // 坐标轴（手动）
    @ColorInt
    protected int mAxisColor = Color.BLACK;
    protected float mAxisThickness = 3f;

    // 网格线（手动）
    protected float mGridsBasicX = 100f;
    protected float mGridsBasicY = 100f;
    protected float mGridsBasicKeepX = 100f;
    protected float mGridsBasicKeepY = 100f;
    @ColorInt
    protected int mGridsColor = Color.GRAY;
    protected float mGridsThickness = 1f;

    // 坐标轴标签（手动）
    protected String mAxisLabelX = "x";
    protected String mAxisLabelY = "y";
    @ColorInt
    protected int mAxisLabelTextColor = Color.BLACK;
    protected float mAxisLabelTextSize = DimenUtils.sp2px(getContext(), 12f);
    protected Typeface mAxisLabelTypeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD_ITALIC);

    // 刻度列表（手动）
    protected AxisScales mAxisScalesX = new LinearAxisScales(-100f, 1f, 200, 100, 0);
    protected AxisScales mAxisScalesY = new LinearAxisScales(-100f, 1f, 200, 100, 0);

    //  刻度列表标签（手动）
    @ColorInt
    protected int mAxisScalesLabelTextColor = Color.DKGRAY;
    protected float mAxisScalesLabelTextSize = DimenUtils.sp2px(getContext(), 9f);
    protected Typeface mAxisScalesLabelTypeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL);

    // 线程绘图
    private Thread mThread;
    private Canvas mCanvas;
    private SurfaceHolder mHolder;
    private boolean mIsDrawing;
    @ColorInt
    private int mBackgroundColor = Color.WHITE;

    // 缩放事件
    private boolean mIsScaling = false;
    private final ScaleGestureDetector mScaleGestureDetector = new ScaleGestureDetector(getContext(),
            new ScaleGestureDetector.OnScaleGestureListener() {
                @Override
                public boolean onScale(ScaleGestureDetector detector) {
                    return onScaleGesture(detector.getFocusX(), detector.getFocusY(), detector.getScaleFactor());
                }

                @Override
                public boolean onScaleBegin(ScaleGestureDetector detector) {
                    mIsScaling = true;
                    return true;
                }

                @Override
                public void onScaleEnd(ScaleGestureDetector detector) {
                    mIsScaling = false;
                }
            });


    // 滑动事件
    private final GestureDetector mScrollGestureDetector = new GestureDetector(getContext(),
            new GestureDetector.SimpleOnGestureListener() {
                @Override
                public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                    if (mIsScaling) {
                        return false;
                    }
                    return onScrollGesture(e1.getX(), e1.getY(), distanceX, distanceY);
                }
            });

    public AbstractCoordinatesView(Context context) {
        this(context, null);
    }

    public AbstractCoordinatesView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public AbstractCoordinatesView(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr,0);
    }

    public AbstractCoordinatesView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        mHolder = getHolder();
        setFocusable(true);
        setKeepScreenOn(true);
        setFocusableInTouchMode(true);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mHolder.addCallback(this);
    }

    /**
     * 将坐标系中的坐标转换为Canvas的实际坐标
     */
    protected abstract float getCanvasX(float x);

    protected abstract float getCanvasY(float y);

    protected PointF getCanvasPointF(PointF point) {
        return new PointF(getCanvasX(point.x), getCanvasY(point.y));
    }

    /**
     * 将Canvas的实际坐标转换为坐标系中的坐标
     */
    protected abstract float getCoordinatesX(float x);

    protected abstract float getCoordinatesY(float y);

    protected PointF getCoordinatesPointF(PointF point) {
        return new PointF(getCoordinatesX(point.x), getCoordinatesY(point.y));
    }

    /**
     * 缩放手势处理,控制坐标系的缩放
     *
     * @param focusX  焦点的X坐标
     * @param focusY  焦点的Y坐标
     * @param factory 缩放因子，小于1时代表缩小，大于1时代表放大
     * @return Boolean 是否进行了事件处理
     */
    protected abstract boolean onScaleGesture(float focusX, float focusY, float factory);

    /**
     * 滑动手势处理,控制坐标系的上下左右滑动
     *
     * @param startX    起点的X坐标
     * @param startY    起点的Y坐标
     * @param distanceX 滑动距离的X轴投影，等于起点的X坐标 - 当前触摸点的X坐标
     * @param distanceY 滑动距离的Y轴投影，等于起点的Y坐标 - 当前触摸点的Y坐标
     * @return Boolean 是否进行了事件处理
     */
    protected abstract boolean onScrollGesture(float startX, float startY, float distanceX, float distanceY);


    /**
     * 触摸事件，包含缩放事件和滑动事件
     * 应优先处理缩放手势，然后再处理滑动手势
     * 缩放手势为双触点手势，滑动手势为单触点手势，两者冲突
     * 在处理缩放手势时屏蔽滑动手势来防止冲突
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mScaleGestureDetector.onTouchEvent(event);
        mScrollGestureDetector.onTouchEvent(event);
        return true;
    }

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        mIsDrawing = true;
        mThread = new Thread(this);
        mThread.start();
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
        // do nothing
    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        mIsDrawing = false;
        try {
            mThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        mThread = null;
    }

    /**
     * 设置绘图背景颜色
     */
    @Override
    public void setBackgroundColor(int color) {
        if (mBackgroundColor != color) {
            mBackgroundColor = color;
            invalidate();
        }
    }

    /**
     * 线程绘图，绘制图形（代替onDraw方法）
     */
    protected abstract void onThreadDraw(Canvas canvas);

    /**
     * 绘图线程
     */
    @Override
    public void run() {
        while (mIsDrawing) {
            try {
                mCanvas = mHolder.lockCanvas();
                if (mCanvas != null) {
                    // 开始绘制，获取的Canvas保存了之前绘制的痕迹
                    mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
                    // 绘制背景颜色
                    if (mBackgroundColor != Color.TRANSPARENT) {
                        mCanvas.drawColor(mBackgroundColor);
                    }
                    onThreadDraw(mCanvas);
                }
            } finally {
                // 绘制结束，提交绘制的Canvas
                if (mCanvas != null) {
                    mHolder.unlockCanvasAndPost(mCanvas);
                }
            }
        }
    }
}
